// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: declaration of CImplNodeBinding.
//   $Id$

#pragma once
#include "formcontrol.h"

class CVertex;
class CImplBind;
class CXFormsParseCommonBinding;

class CImplNodeBinding: public CFormControl
{
	friend class CXFormsParseCommonBinding;
//This is the base class for NodeSetBinding and SingleNodeBinding.
//	many of the properties of FormControl, including m_pModel, m_sModel 
//	 etc. should be moved into here.

public:
	CImplNodeBinding();
	CImplNodeBinding(CXFormsElement * pElement);
	virtual ~CImplNodeBinding();

	virtual void disconnect(CBoundNode* pNode);
	bool m_bInParentContext;
	virtual bool AddControl(CImplNodeBinding * pControl);
	inline void RemoveControl(CImplNodeBinding * pControl);

	virtual HRESULT blank();
	virtual HRESULT doInitialize();
	CImplBind * m_pBind;
	virtual void buildDependencies();
	bool m_bApplyFirstNodeRule;
	virtual HRESULT init(CImpl*pParent);
//	virtual bool reliesOnParent();
	virtual HRESULT GetEvaluationContext(IXMLDOMNode ** ppNode);

	HRESULT getModel();
	//kept until there is a common name for m_sNodeset and m_sRef
	BSTR * m_pbsXPathExpression;
	//In the case of a SingleNodeBinding, this will only have one vertex
	//	but in a nodeset, it will have many.
	CTypedPtrArray<CPtrArray,CVertex*> m_vertices;
	HRESULT formControlInitialize();

	//TODO: make private by removing its use in CXFormsElementRepeat::createIteration
	CComBSTR m_sModel;


	virtual void setModel(CImplModel*  pModel);
/*
Not yet implemented, see comment in BindingTargetImpl.cpp
	//Events from IBindingTarget:
	//	These are dispatched in response
	//	to changes in state in the DOM
	virtual HRESULT oninvalid();
	virtual HRESULT onvalid();
	virtual HRESULT onreadonly();
	virtual HRESULT onreadwrite();
	virtual HRESULT onrequired();
	virtual HRESULT onoptional();
	virtual HRESULT onenabled();
	virtual HRESULT ondisabled();
	virtual HRESULT onvaluechanged();
	*/
	//These two made public for CImplBind.
	//<summary>
	//	Called at the end of buildDependencies to clear m_OldNodes and
	//	m_bDoingBinding, and allow normal processing to continue.
	//</summary>
	void ConfirmBindings();
	//<summary>
	//	For the duration of buildDependencies, m_OldNodes contains 
	//	pointers to the nodes from the last binding (i.e. before the rebuild).
	//</summary>
	CTypedPtrArray<CPtrArray,CBoundNode *> m_OldNodes;

	// A control may not receive focus if it is bound to an irrelevant or non-existant node
	virtual bool receiveFocus(void);
	BSTR GenerateDebugDisplayInfo(void);
	BSTR getFullXPath(void) const;
	void ClearBindings(void);
protected:
	CComBSTR m_sBind;
	CTypedPtrList<CPtrList, CImplNodeBinding*> m_ReliantControls;
	bool m_bCanBindToValue;
	//<summary>
	//	flag set in ClearBindings and ConfirmBindings
	//</summary>
	//<remarks>
	//	This is to prevent the endless loop/stack overflow
	//	described in bug 932.
	//	
	//	When a rebuild occurs, and a node binding does not change,
	//	none of the state-change events should be handled on that
	//	control.
	//
	//	Note that it is important that this occurs on the control,
	//	not the node itself.  The node must be free to have targets 
	//	bound and unbound, as well as dispatch events to any targets.
	//	
	//</remarks>
	//bool m_bReceiveStateChangeEvents;
	virtual bool IsAppropriateToInitializeNow();


private:
	void buildChildDependencies();
	HRESULT getContextParent(CImplNodeBinding ** pContextParent);
	bool m_bPartInitialized;
	wchar_t *m_lpwszControlID;
	HANDLE m_hInRebuild;
};

inline void CImplNodeBinding::RemoveControl(CImplNodeBinding *pControl)
{
	POSITION pos = m_ReliantControls.Find(pControl);
	if(pos)
		m_ReliantControls.RemoveAt(pos);
}


